package controllers;

import constants.*;
import hibernate.*;
import interfaces.IDbController;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import javax.swing.JOptionPane;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;

/**
 *
 * @author Kurt
 */
public final class DbController implements IDbController {

    public DbController() {
        try {
            validateDb();
        } catch (Exception e) {
            JOptionPane.showMessageDialog(null, "Database problem..  Ensure your config file\n is correct and the database server is accessible...\nThe application cannot run without the database\n and will now exit.");
            System.exit(0);
        }


    }

    private void validateDb() {

        Configuration config = new Configuration();
        if (getDbDataCount(User.class) < 1) {
            config.configure();
            new SchemaExport(config).create(true, true);
            addAdmin();
        }
    }

    private void addAdmin() {

        Date d = new Date();
        User u = new User();
        u.setCommonName("admin");
        u.setFirstName("admin");
        u.setLastName("admin");
        u.setPassword("admin");
        u.setCreateDate(d);
        u.setLibraryId(0);
        u.setUserAccess(UserTypes.ADMIN.VALUE());

        saveDbData(u);
    }

    public User validLogin(User u) {

        List l = getDbData(User.class, null);
        User t = new User();
        for (Iterator i = l.iterator(); i.hasNext();) {
            t = (User) i.next();
            if ((t.getUserAccess() == UserTypes.ADMIN.VALUE()) || (t.getUserAccess() == UserTypes.STUDENT.VALUE())) {
                l.remove(i);
            } else {
                if (t.getCommonName().matches(u.getCommonName())) {
                    return t;
                }
            }
        }
        return null;
    }

    public int getNextIndex(Class c, String indexName) {
        List l = getDbData(c, null);
        int v = 0;

        for (Iterator i = l.iterator(); i.hasNext();) {
            if (c.toString().equals("User")) {
                User t;
                t = (User) i.next();
                if (v < t.getIndex(indexName)) {
                    v = t.getIndex(indexName);
                }
            }
        }
        return v;
    }

    @Override
    public void saveDbData(Object o) {
        Session s = createSession();
        s.createCriteria(o.getClass());
        s.beginTransaction();
        s.save(o);
        s.getTransaction().commit();
        s.close();
    }

    public void updateDbData(Object o) {
        Session s = createSession();
        updateFileInformation(o);
        s.createCriteria(o.getClass());
        s.beginTransaction();
        s.update(o);
        s.getTransaction().commit();
        s.close();
    }

    public void deleteDbData(Object o) {
        Session s = createSession();
        s.createCriteria(o.getClass());
        s.beginTransaction();
        s.delete(o);
        s.getTransaction().commit();
        s.close();
    }

    @Override
    public List getDbData(Class c, Object o) {

        List list = new ArrayList();
        List fullList = new ArrayList();
        Session s = createSession();
        s.createCriteria(c.getClass());
        s.beginTransaction();
        list = s.createQuery("from " + c.getSimpleName()).list();
        s.getTransaction().commit();
        s.close();
        fullList = populateFileInfo(list);
        return fullList;
    }

    private void updateFileInformation(Object o) {

        if (o.getClass().equals(Activity.class)) {
            Activity a = (Activity) o;

            if (a.getImageName().contains(Global.activityImagePath)) {

                copyFile(a.getImage(), a.getImageName());

            } else {

                File image = a.getImage();
                String newImageName = Global.activityImagePath + "/" + generateUniqueFileName(a, Global.activityImagePath);
                copyFile(image, newImageName);
                a.setImageName(newImageName);

            }

            if (a.getPhonetic().contains(Global.activitySoundPath)) {

                copyFile(a.getSound(), a.getPhonetic());

            } else {

                File sound = a.getSound();
                String newSoundName = Global.activitySoundPath + "/" + generateUniqueFileName(a, Global.activitySoundPath);
                copyFile(sound, newSoundName);
                a.setPhonetic(newSoundName);

            }
        }

        if (o.getClass().equals(User.class)) {
            User u = (User) o;

            if (u.getImagePath().contains(Global.userImagePath)) {

                copyFile(u.getImage(), u.getImagePath());

            } else {

                File image = u.getImage();
                String newImageName = Global.userImagePath + "/" + generateUniqueFileName(u, Global.userImagePath);
                copyFile(image, newImageName);
                u.setImagePath(newImageName);

            }
        }


    }

    private List populateFileInfo(List l) {
        List list = l;
        Object o = null;
        for (Iterator i = list.iterator(); i.hasNext();) {
            o = i.next();
            if (o.getClass().equals(User.class)) {
                User u = (User) o;
                u.setImage(getFile(u.getImagePath()));
                if ((u.getTeacherId() != null) && u.getTeacherId() > 0) {
                    u.setSchedules(getStudentSchedules(u));
                    u.setImage(getFile(u.getImagePath()));
                }
            }

            if (o.getClass().equals(Activity.class)) {
                Activity a = (Activity) o;
                a.setImage(getFile(a.getImageName()));
                a.setSound(getFile(a.getPhonetic()));
            }

            if (o.getClass().equals(ScheduledActivity.class)) {
                ScheduledActivity a = (ScheduledActivity) o;
                a.setImage(getFile(a.getImageName()));
                a.setSound(getFile(a.getPhonetic()));
            }

        }


        return list;
    }

    private File getFile(String path) {

        if ((path == null) || path.equals("")) {
            return null;
        }
        if (new File(path).exists()) {
            File f = new File(path);
            return f;
        }
        return null;

    }

    private List getStudentSchedules(User u) {
        List l = new ArrayList();
        List userSchedules = new ArrayList();
        l = this.getDbData(Schedule.class, null);
        for (Iterator i = l.iterator(); i.hasNext();) {
            Schedule s = (Schedule) i.next();
            if (s.getUserId() == u.getUserId()) {
                s.setActivities(getScheduledActivities(s));
                userSchedules.add(s);
            }
        }
        l = populateFileInfo(userSchedules);
        userSchedules = l;
        return userSchedules;

    }

    private List getScheduledActivities(Schedule s) {
        List l = new ArrayList();
        List userScheduledActivities = new ArrayList();
        l = this.getDbData(ScheduledActivity.class, null);
        for (Iterator i = l.iterator(); i.hasNext();) {
            ScheduledActivity a = (ScheduledActivity) i.next();
            if (a.getSchedId() == s.getSchedId()) {
                userScheduledActivities.add(a);
            }
        }
        return userScheduledActivities;
    }

    @Override
    public int getDbDataCount(Class o) {
        try {
            Session s = createSession();
            s.beginTransaction();
            Long count = (Long) s.createQuery("select count(*) from " + o.getSimpleName()).uniqueResult();
            s.getTransaction().commit();
            s.close();
            return count.intValue();
        } catch (Exception e) {
            return -1;
        }
    }

    private Session createSession() {
        try {
            SessionFactory sf = new Configuration().configure().buildSessionFactory();
            Session s = sf.openSession();
            return s;
        } catch (Exception e) {
        }
        return null;
    }

    /*
     * Each class that needs to have unique stuff in it should use this function
     * to determine whether it is unique in it's list.  The required classes
     * will have the Comparable interface implemented.  At the top of each of
     * classes, I will annotate why it should be unique.  Let me know if you
     * find any problems with it.
     */
    public boolean isObjectUnique(List l, Object o) {
        Comparable s = (Comparable) o;
        List tempList = new ArrayList();
        tempList.addAll(l);
        for (Iterator i = tempList.iterator(); i.hasNext();) {
            if (s.compareTo(o) == 0) {
                return false;
            }
        }
        return true;
    }

    public Object copyImageAndSoundFiles(File image, File sound, Object o) {

        if (o.getClass().equals(Activity.class)) {

            Activity a = (Activity) o;

            String newImageName = Global.activityImagePath + "/" + generateUniqueFileName(a, Global.activityImagePath);
            String newSoundName = Global.activitySoundPath + "/" + generateUniqueFileName(a, Global.activitySoundPath);

            copyFile(image, newImageName);
            copyFile(sound, newSoundName);

            a.setPhonetic(newSoundName);
            a.setImageName(newImageName);
            o = a;
        }

        if (o.getClass().equals(User.class)) {
            User u = (User) o;

            String newUserImageName = Global.userImagePath + "/" + generateUniqueFileName(u, Global.userImagePath);
            copyFile(image, newUserImageName);
            u.setImagePath(newUserImageName);
            o = u;
        }



        return o;

    }

    public void copyFile(File f, String name) {

        try {
            InputStream oInStream = new FileInputStream(f);
            OutputStream oOutStream = new FileOutputStream(name);

            // Transfer bytes from in to out
            byte[] oBytes = new byte[1024];
            int nLength;
            BufferedInputStream oBuffInputStream =
                    new BufferedInputStream(oInStream);
            while ((nLength = oBuffInputStream.read(oBytes)) > 0) {
                oOutStream.write(oBytes, 0, nLength);
            }
            oInStream.close();
            oOutStream.close();
        } catch (Exception e) {
        }


    }

    public String generateUniqueFileName(Object o, String path) {

        int value = -1;
        String uniqueName = "";
        List l = new ArrayList();



            if (path.equals(Global.userImagePath)) {

                User u = (User) o;
                l = this.getDbData(User.class, null);
                if (u.getUserId() > 0) {
                    value = u.getUserId();
                } else {
                    int hiIndex = 0;
                    for (Iterator i = l.iterator(); i.hasNext();) {
                        u = (User) i.next();
                        if (hiIndex < u.getUserId()) {
                            hiIndex = u.getUserId();
                        }
                    }
                    value = hiIndex + 1;
                }
                uniqueName = "UserImage_" + value;
                
            }

            if (path.equals(Global.activityImagePath)) {

                Activity u = (Activity) o;
                Activity a;
                l = this.getDbData(Activity.class, null);
                if (u.getActivityId() > 0) {
                    value = u.getActivityId();

                } else {
                    int hiIndex = 0;
                    for (Iterator i = l.iterator(); i.hasNext();) {
                        a = (Activity) i.next();
                        if (hiIndex < a.getActivityId()) {
                            hiIndex = a.getActivityId();
                        }
                    }
                    value = hiIndex + 1;

                }
                uniqueName = "ActivityImage_" + value;
                
            }
            if (path.equals(Global.activitySoundPath)) {

                Activity u = (Activity) o;
                Activity a;
                l = this.getDbData(Activity.class, null);
                int hiIndex = 0;
                for (Iterator i = l.iterator(); i.hasNext();) {
                    a = (Activity) i.next();
                    if (hiIndex < a.getActivityId()) {
                        hiIndex = a.getActivityId();
                    }
                }
                value = hiIndex + 1;
            
                uniqueName = "ActivitySound_" + value;
        }

        return uniqueName;
    }
}
